🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / ui / src / commonTest / kotlin / org / meshtastic / core / ui / component / AdaptiveTwoPaneUiTest.kt
Displaying Raw • Download
core/ui/src/commonTest/kotlin/org/meshtastic/core/ui/component/AdaptiveTwoPaneUiTest.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 5.26 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.ui.component
Tff7b72import T7ee787androidx.compose.foundation.layout.Box
Tff7b72import T7ee787androidx.compose.foundation.layout.fillMaxSize
Tff7b72import T7ee787androidx.compose.foundation.lazy.LazyColumn
Tff7b72import T7ee787androidx.compose.foundation.rememberScrollState
Tff7b72import T7ee787androidx.compose.foundation.verticalScroll
Tff7b72import T7ee787androidx.compose.material3.Text
Tff7b72import T7ee787androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
Tff7b72import T7ee787androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
Tff7b72import T7ee787androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective
Tff7b72import T7ee787androidx.compose.runtime.getValue
Tff7b72import T7ee787androidx.compose.runtime.mutableStateOf
Tff7b72import T7ee787androidx.compose.runtime.setValue
Tff7b72import T7ee787androidx.compose.ui.Modifier
Tff7b72import T7ee787androidx.compose.ui.geometry.Offset
Tff7b72import T7ee787androidx.compose.ui.test.ExperimentalTestApi
Tff7b72import T7ee787androidx.compose.ui.test.assertIsDisplayed
Tff7b72import T7ee787androidx.compose.ui.test.onNodeWithTag
Tff7b72import T7ee787androidx.compose.ui.test.onNodeWithText
Tff7b72import T7ee787androidx.compose.ui.test.performTouchInput
Tff7b72import T7ee787androidx.compose.ui.test.v2.runComposeUiTest
Tff7b72import T7ee787org.meshtastic.core.ui.theme.AppTheme
Tff7b72import T7ee787kotlin.math.abs
Tff7b72import T7ee787kotlin.test.Test
Tff7b72import T7ee787kotlin.test.assertTrue
Tf0883e@OptInTb4b4b4(Te6edf3ExperimentalTestApiTff7b72::Te6edf3classTb4b4b4, Te6edf3ExperimentalMaterial3AdaptiveApiTff7b72::Te6edf3classTb4b4b4)
Tff7b72class T56d364AdaptiveTwoPaneUiTest Tb4b4b4{
T8b949e// Crashlytics 788308c5 (fatal, tablets): the split scaffold echoed the LazyColumn item's infinite
T8b949e// max height as its size ("Size(1608 x 2147483647) is out of range"). Must render, not crash.
Tf0883e@Test
Tff7b72fun Td2a8ffsplitPaneInsideLazyColumnItemRendersBothPanesTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runComposeUiTest Tb4b4b4{
Tff7b72var Te6edf3horizontalPartitions Tff7b72= T79c0ff0
Te6edf3setContent Tb4b4b4{
Te6edf3AppTheme Tb4b4b4{
Te6edf3horizontalPartitions Tff7b72=
Te6edf3calculatePaneScaffoldDirectiveTb4b4b4(Te6edf3currentWindowAdaptiveInfoV2Tb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3maxHorizontalPartitions
Te6edf3LazyColumn Tb4b4b4{
Te6edf3item Tb4b4b4{ Te6edf3AdaptiveTwoPaneTb4b4b4(Te6edf3first Tff7b72= Tb4b4b4{ Te6edf3TextTb4b4b4(Ta5d6ff"Ta5d6fffirst paneTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4, Te6edf3second Tff7b72= Tb4b4b4{ Te6edf3TextTb4b4b4(Ta5d6ff"Ta5d6ffsecond paneTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
T8b949e// The default test window is expanded-width; without this the regression path is not exercised.
Te6edf3assertTrueTb4b4b4(Te6edf3horizontalPartitions Tff7b72> T79c0ff1Tb4b4b4, Ta5d6ff"Ta5d6ffexpected an expanded-width test windowTa5d6ff"Tb4b4b4)
Te6edf3onNodeWithTextTb4b4b4(Ta5d6ff"Ta5d6fffirst paneTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3assertIsDisplayedTb4b4b4(Tb4b4b4)
Te6edf3onNodeWithTextTb4b4b4(Ta5d6ff"Ta5d6ffsecond paneTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3assertIsDisplayedTb4b4b4(Tb4b4b4)
T8b949e// No drag handle: the unbounded host must get the Row fallback, not the scaffold.
Te6edf3onNodeWithTagTb4b4b4(Te6edf3ADAPTIVE_TWO_PANE_DRAG_HANDLE_TAGTb4b4b4)Tb4b4b4.Te6edf3assertDoesNotExistTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffsplitPaneInBoundedHostRendersBothPanesTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runComposeUiTest Tb4b4b4{
Te6edf3setContent Tb4b4b4{
Te6edf3AppTheme Tb4b4b4{
Te6edf3BoxTb4b4b4(Te6edf3modifier Tff7b72= Te6edf3ModifierTb4b4b4.Te6edf3fillMaxSizeTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3AdaptiveTwoPaneTb4b4b4(Te6edf3first Tff7b72= Tb4b4b4{ Te6edf3TextTb4b4b4(Ta5d6ff"Ta5d6fffirst paneTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4, Te6edf3second Tff7b72= Tb4b4b4{ Te6edf3TextTb4b4b4(Ta5d6ff"Ta5d6ffsecond paneTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Te6edf3onNodeWithTextTb4b4b4(Ta5d6ff"Ta5d6fffirst paneTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3assertIsDisplayedTb4b4b4(Tb4b4b4)
Te6edf3onNodeWithTextTb4b4b4(Ta5d6ff"Ta5d6ffsecond paneTa5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3assertIsDisplayedTb4b4b4(Tb4b4b4)
T8b949e// The drag handle proves the bounded host kept the SupportingPaneScaffold branch.
Te6edf3onNodeWithTagTb4b4b4(Te6edf3ADAPTIVE_TWO_PANE_DRAG_HANDLE_TAGTb4b4b4)Tb4b4b4.Te6edf3assertExistsTb4b4b4(Tb4b4b4)
Tb4b4b4}
T8b949e// The pane expansion state is hoisted above the height branch, so a divider the user dragged must
T8b949e// survive the host flipping to unbounded constraints (scaffold disposed) and back.
Tf0883e@Test
Tff7b72fun Td2a8ffdividerPositionSurvivesBoundedUnboundedRoundTripTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runComposeUiTest Tb4b4b4{
Tff7b72var Te6edf3bounded Tff7b72by Te6edf3mutableStateOfTb4b4b4(Tff7b72trueTb4b4b4)
Te6edf3setContent Tb4b4b4{
Te6edf3AppTheme Tb4b4b4{
Tff7b72val Te6edf3hostModifier Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3boundedTb4b4b4) Te6edf3ModifierTb4b4b4.Te6edf3fillMaxSizeTb4b4b4(Tb4b4b4) Tff7b72else Te6edf3ModifierTb4b4b4.Te6edf3verticalScrollTb4b4b4(Te6edf3rememberScrollStateTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3BoxTb4b4b4(Te6edf3modifier Tff7b72= Te6edf3hostModifierTb4b4b4) Tb4b4b4{
Te6edf3AdaptiveTwoPaneTb4b4b4(Te6edf3first Tff7b72= Tb4b4b4{ Te6edf3TextTb4b4b4(Ta5d6ff"Ta5d6fffirst paneTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4, Te6edf3second Tff7b72= Tb4b4b4{ Te6edf3TextTb4b4b4(Ta5d6ff"Ta5d6ffsecond paneTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72val Te6edf3handle Tff7b72= Te6edf3onNodeWithTagTb4b4b4(Te6edf3ADAPTIVE_TWO_PANE_DRAG_HANDLE_TAGTb4b4b4)
Tff7b72val Te6edf3initialX Tff7b72= Te6edf3handleTb4b4b4.Te6edf3fetchSemanticsNodeTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3boundsInRootTb4b4b4.Te6edf3centerTb4b4b4.Te6edf3x
Te6edf3handleTb4b4b4.Te6edf3performTouchInput Tb4b4b4{
Te6edf3downTb4b4b4(Te6edf3centerTb4b4b4)
Te6edf3moveByTb4b4b4(Te6edf3OffsetTb4b4b4(Tff7b72-T79c0ff2T79c0ff0T79c0ff0fTb4b4b4, T79c0ff0fTb4b4b4)Tb4b4b4)
Te6edf3upTb4b4b4(Tb4b4b4)
Tb4b4b4}
Te6edf3waitForIdleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3draggedX Tff7b72= Te6edf3handleTb4b4b4.Te6edf3fetchSemanticsNodeTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3boundsInRootTb4b4b4.Te6edf3centerTb4b4b4.Te6edf3x
Te6edf3assertTrueTb4b4b4(Te6edf3absTb4b4b4(Te6edf3draggedX Tff7b72- Te6edf3initialXTb4b4b4) Tff7b72> T79c0ff5T79c0ff0fTb4b4b4, Ta5d6ff"Ta5d6ffexpected the drag to move the dividerTa5d6ff"Tb4b4b4)
Te6edf3bounded Tff7b72= Tff7b72false
Te6edf3waitForIdleTb4b4b4(Tb4b4b4)
Te6edf3handleTb4b4b4.Te6edf3assertDoesNotExistTb4b4b4(Tb4b4b4)
Te6edf3bounded Tff7b72= Tff7b72true
Te6edf3waitForIdleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3restoredX Tff7b72= Te6edf3handleTb4b4b4.Te6edf3fetchSemanticsNodeTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3boundsInRootTb4b4b4.Te6edf3centerTb4b4b4.Te6edf3x
Te6edf3assertTrueTb4b4b4(Te6edf3absTb4b4b4(Te6edf3restoredX Tff7b72- Te6edf3draggedXTb4b4b4) Tff7b72< T79c0ff3fTb4b4b4, Ta5d6ff"Ta5d6ffdivider was at Tffd700$Te6edf3draggedXTa5d6ff but came back at Tffd700$Te6edf3restoredXTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.05s